home *** CD-ROM | disk | FTP | other *** search
/ SuperHack / SuperHack CD.bin / CODING / GRAPHICS / EASY_3D.ZIP / EASY_3D.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1994-02-23  |  12.4 KB  |  373 lines

  1. PROGRAM EASY_3D;
  2.  
  3. {
  4.    Very simple source code to illustrate 3D-rotations and delay-vektorz
  5.    Do what ya want with it.. its totally free..
  6.  
  7.    It's just a 'one-hour' type project, enough time to write it down in
  8.    the editor, fix the typo errors and comment it... so ya should not
  9.    expect it to make somme coffee or anything else than giving a concrete
  10.    example of VERY basic 3D calculus.
  11.  
  12.    Oh yes! It has been tested only in 640*480 VGA, so in other modes there
  13.    might be some problems..
  14.  
  15.  
  16.              Code By
  17.  
  18.    (\ )  /) |_)  /) )   (\/)
  19.    ( \) / ) |   / ) \__ (  )
  20. }
  21.  
  22.  
  23.  
  24. Uses Crt, Graph;
  25.  
  26. Type
  27.  
  28.     Vect3D              =   Array[1..3] of LongInt;
  29.     Mat33               =   Array[1..3,1..3] of LongInt;
  30.  
  31.     Point2D             =   Record
  32.                                   X,Y : LongInt;
  33.                             End;
  34.     Point3D             =   Record
  35.                                   X,Y,Z : LongInt;
  36.                             End;
  37.  
  38.     Poly3D_3            =   Array[1..3] of Point3D;
  39.     Poly3D_4            =   Array[1..4] of Point3D;
  40.     Poly2D_3            =   Array[1..3] of Point2D;
  41.     Poly2D_4            =   Array[1..4] of Point2D;
  42.  
  43. Var
  44.     Face, FaceRot       : Poly3D_4;{ Original coords / Rotated coords }
  45.  
  46.     FaceProj, OldProj,
  47.     OldProj2, OldProj3,
  48.     OldProj4            : Poly2D_4;{ Projected coords / "Delay" coords }
  49.  
  50.     RotXYZ              : Mat33;   { Rotation matrix around X, Y & Z }
  51.  
  52.     angle_x, angle_y,
  53.     angle_z             : Integer; { Angles of rotations around X, Y & Z }
  54.  
  55.     dist2screen         : Integer; { Distance from Eye/Viewpoint to screen }
  56.  
  57.     xi, yi, zi          : byte;    { Increments for angles / Rotation speed }
  58.     oldxi, oldyi, oldzi : byte;
  59.  
  60.     Fin, Frozen         : Boolean;
  61.  
  62. Const
  63.     Maxli               = 10;
  64.     usage               : Array[1..Maxli] of string =
  65.                         ('╔═════════════════════╗',
  66.                          '║                     ║',
  67.                          '╟─────╥───────────────╨─────────╖',
  68.                          '║ 8,2 ║  X axis rotation speed  ║',
  69.                          '║ 4,6 ║  Y axis rotation speed  ║',
  70.                          '║ 9,1 ║  Z axis rotation speed  ║',
  71.                          '║ +,- ║  Zoom in / Zoom out     ║',
  72.                          '║  F  ║  Freeze / Unfreeze      ║',
  73.                          '║ ESC ║  Get Out !              ║',
  74.                          '╚═════╩═════════════════════════╝');
  75.  
  76.  
  77. (*------------------------------------------------------------------------*)
  78. { Initialize the video mode }
  79.  
  80. PROCEDURE InitVid;
  81. var gd,gm : integer;
  82. Begin
  83.      Gd:=Detect;
  84.      InitGraph(Gd,Gm,'');
  85.      If GraphResult<>GrOk then halt;
  86.  
  87.      SetLineStyle( SolidLn, 1, ThickWidth);
  88. End;
  89. (*------------------------------------------------------------------------*)
  90. { Initialize coordinates of the plane (=Face) }
  91.  
  92. PROCEDURE InitFace;
  93. Var i : byte;
  94. Begin
  95.      Face[1].X:=10;
  96.      Face[1].Y:=10;
  97.      Face[1].Z:=0;
  98.      Face[2].X:=10;
  99.      Face[2].Y:=-10;
  100.      Face[2].Z:=0;
  101.      Face[3].X:=-10;
  102.      Face[3].Y:=-10;
  103.      Face[3].Z:=0;
  104.      Face[4].X:=-10;
  105.      Face[4].Y:=10;
  106.      Face[4].Z:=0;
  107.  
  108.      For i:=1 to 4 do
  109.          Begin
  110.               OldProj[i].X:=Face[i].X;
  111.               OldProj[i].Y:=Face[i].Y;
  112.               OldProj2[i].X:=Face[i].X;
  113.               OldProj2[i].Y:=Face[i].Y;
  114.               OldProj3[i].X:=Face[i].X;
  115.               OldProj3[i].Y:=Face[i].Y;
  116.               OldProj4[i].X:=Face[i].X;
  117.               OldProj4[i].Y:=Face[i].Y;
  118.          End;
  119. End;
  120. (*------------------------------------------------------------------------*)
  121. { Multiply all 4 points of the plane by 3x3 Matrix }
  122.  
  123. PROCEDURE MAT_MUL_FACE( SF : Poly3D_4; VAR DF : Poly3D_4; MAT : Mat33);
  124. var i : byte;
  125.  
  126. Begin
  127.    DF[1].X:=SF[1].X * MAT[1][1] + SF[1].Y * MAT[1][2] + SF[1].Z * MAT[1][3];
  128.    DF[1].Y:=SF[1].X * MAT[2][1] + SF[1].Y * MAT[2][2] + SF[1].Z * MAT[2][3];
  129.    DF[1].Z:=SF[1].X * MAT[3][1] + SF[1].Y * MAT[3][2] + SF[1].Z * MAT[3][3];
  130.  
  131.    DF[2].X:=SF[2].X * MAT[1][1] + SF[2].Y * MAT[1][2] + SF[2].Z * MAT[1][3];
  132.    DF[2].Y:=SF[2].X * MAT[2][1] + SF[2].Y * MAT[2][2] + SF[2].Z * MAT[2][3];
  133.    DF[2].Z:=SF[2].X * MAT[3][1] + SF[2].Y * MAT[3][2] + SF[2].Z * MAT[3][3];
  134.  
  135.    DF[3].X:=SF[3].X * MAT[1][1] + SF[3].Y * MAT[1][2] + SF[3].Z * MAT[1][3];
  136.    DF[3].Y:=SF[3].X * MAT[2][1] + SF[3].Y * MAT[2][2] + SF[3].Z * MAT[2][3];
  137.    DF[3].Z:=SF[3].X * MAT[3][1] + SF[3].Y * MAT[3][2] + SF[3].Z * MAT[3][3];
  138.  
  139.    DF[4].X:=SF[4].X * MAT[1][1] + SF[4].Y * MAT[1][2] + SF[4].Z * MAT[1][3];
  140.    DF[4].Y:=SF[4].X * MAT[2][1] + SF[4].Y * MAT[2][2] + SF[4].Z * MAT[2][3];
  141.    DF[4].Z:=SF[4].X * MAT[3][1] + SF[4].Y * MAT[3][2] + SF[4].Z * MAT[3][3];
  142. End;
  143. (*------------------------------------------------------------------------*)
  144. { 3D to 2D plane coordinates projection }
  145.  
  146. PROCEDURE PROJ_FACE( SF : Poly3D_4; VAR DF : Poly2D_4; tot : Integer);
  147. Var factor : Byte;
  148.     dosc : LongInt;
  149.  
  150. Begin
  151.  
  152.      dosc:=dist2screen;
  153.      factor:=50;
  154.  
  155.      SF[1].Z:=(dosc+5)*16384;
  156.      DF[1].X:=Round(factor * SF[1].X / SF[1].Z);
  157.      DF[1].Y:=Round(factor * SF[1].Y / SF[1].Z);
  158.  
  159.      SF[2].Z:=(5+dosc)*16384;
  160.      DF[2].X:=Round(factor * SF[2].X / SF[2].Z);
  161.      DF[2].Y:=Round(factor * SF[2].Y / SF[2].Z);
  162.  
  163.      SF[3].Z:=(5+dosc)*16384;
  164.      DF[3].X:=Round(factor * SF[3].X / SF[3].Z);
  165.      DF[3].Y:=Round(factor * SF[3].Y / SF[3].Z);
  166.  
  167.      SF[4].Z:=(5+dosc)*16384;
  168.      DF[4].X:=Round(factor * SF[4].X / SF[4].Z);
  169.      DF[4].Y:=Round(factor * SF[4].Y / SF[4].Z);
  170.  
  171. End;
  172. (*------------------------------------------------------------------------*)
  173. { Draws a 4 points polygon with 4 points (DrawPoly needs 5) }
  174.  
  175. PROCEDURE DrawP( F : Poly2D_4);
  176. Var oldx, oldy : Word;
  177.  
  178. Begin
  179.      Line( F[1].X, F[1].Y, F[2].X, F[2].Y);
  180.      Line( F[2].X, F[2].Y, F[3].X, F[3].Y);
  181.      Line( F[3].X, F[3].Y, F[4].X, F[4].Y);
  182.      Line( F[4].X, F[4].Y, F[1].X, F[1].Y);
  183. End;
  184. (*------------------------------------------------------------------------*)
  185. { Displays a 4 points polygon on screen with "delay" display of old  }
  186. { positions ...                                                      }
  187.  
  188. PROCEDURE DRAW_FACE( SF : Poly2D_4);
  189. var i : byte;
  190. Begin
  191.  
  192. {
  193.   Oh yeah! This is not beautiful code (far from it !!) but the effect is
  194.   cute... A linked list would prevent all those unoptimized data-moves
  195.   but again this code is here just to illustrate 3D rotations...
  196. }
  197.  
  198.      SetColor(0);
  199.      DrawP( OldProj);
  200.      SetColor( 1);
  201.      DrawP( OldProj2);
  202.      SetColor( 9);
  203.      DrawP( OldProj3);
  204.      SetColor( 11);
  205.      DrawP( OldProj4);
  206.  
  207.      For i:=1 to 4 do
  208.          Begin
  209.               SF[i].X:=SF[i].X+320;
  210.               SF[i].Y:=SF[i].Y+240;
  211.          End;
  212.  
  213.      SetColor(15);
  214.      DrawP( SF);
  215.  
  216.      For i:=1 to 4 do
  217.          Begin
  218.               OldProj[i].X:=OldProj2[i].X;
  219.               OldProj[i].Y:=OldProj2[i].Y;
  220.               OldProj2[i].X:=OldProj3[i].X;
  221.               OldProj2[i].Y:=OldProj3[i].Y;
  222.               OldProj3[i].X:=OldProj4[i].X;      {  Yerk ! }
  223.               OldProj3[i].Y:=OldProj4[i].Y;
  224.               OldProj4[i].X:=SF[i].X;
  225.               OldProj4[i].Y:=SF[i].Y;
  226.          End;
  227. End;
  228. (*------------------------------------------------------------------------*)
  229. { Computes the rotation matrix for the given angles, rotates, projects }
  230. { and display the 4 points plane                                       }
  231.  
  232.  
  233. PROCEDURE Rotate( ax, ay, az : Integer; dist_s : Integer);
  234. Var x, y, z : Real;
  235. Begin
  236.      x:=ax * Pi / 180;
  237.      y:=ay * Pi / 180;
  238.      z:=az * Pi / 180;
  239.  
  240. {
  241.      The "magical" MATRIX, rotates a vektor around X-Y-Z a the same
  242.      time.
  243.  
  244.      ┌                                              ┐
  245.      │     cZ*cY               -cY*sZ          sY   │
  246.      │ cX*sZ-sY*cZ*sX      cZ*cX+sX*sZ*sY     cY*sX │
  247.      │-sX*sZ-sY*cZ*cX     -cZ*sX+sZ*sY*cX     cX*cY │
  248.      └                                              ┘
  249.  
  250.      X  -> Rotation angle around X-axis
  251.      Y  -> Rotation angle around Y-axis
  252.      Z  -> Rotation angle around Z-axis
  253.  
  254.      cZ -> COS(Z)   sZ -> SIN(Z)
  255.      cX -> COS(X)   ....
  256.  
  257.      We use here a factor (i.e: 16384) to keep a certain precision
  258.      during calculations as we use 32bit-integers. This code is designed to
  259.      be translated to assembly, where SIN and COS are precalculated and
  260.      where IEEE floating point is to be banned.
  261.  
  262.      Of course during the calculus of projections we divide by 16384.
  263.  
  264.      Why 16384 ?
  265.      If ya know some assembly, this division can be done using arithmetic
  266.      bit-shifts that are very fast compared to signed-division.
  267. }
  268.  
  269.      If NOT ((xi=0) AND (yi=0) AND (zi=0)) then
  270.         Begin
  271.              RotXYZ[1][1]:=Round(cos(z)*cos(y)*16384);
  272.              RotXYZ[1][2]:=Round(-sin(z)*cos(y)*16384);
  273.              RotXYZ[1][3]:=Round(sin(y)*16384);
  274.              RotXYZ[2][1]:=Round((cos(x)*sin(z)-sin(y)*cos(z)*sin(x))*16384);
  275.              RotXYZ[2][2]:=Round((cos(z)*cos(x)+sin(x)*sin(z)*sin(y))*16384);
  276.              RotXYZ[2][3]:=Round(cos(y)*sin(x)*16384);
  277.              RotXYZ[3][1]:=Round((-sin(x)*sin(z)-sin(y)*cos(z)*cos(x))*16384);
  278.              RotXYZ[3][2]:=Round((-cos(z)*sin(x)+sin(z)*sin(y)*cos(x))*16384);
  279.              RotXYZ[3][3]:=Round(cos(x)*cos(y)*16384);
  280.  
  281.              MAT_MUL_FACE( Face, FaceRot, RotXYZ);
  282.              PROJ_FACE( FaceRot, FaceProj, dist_s);
  283.              DRAW_FACE( FaceProj);
  284.         End;
  285. End;
  286. (*------------------------------------------------------------------------*)
  287. { Displays usable commands during animation }
  288.  
  289. PROCEDURE DispDoc;
  290. Var i : byte;
  291. Begin
  292.      SetColor(14);
  293.      OutTextXY( 19,18, 'Available commands');
  294.  
  295.      SetColor(7);
  296.  
  297.      For i:=1 to Maxli do
  298.          OutTextXY( 2, 2+i*8, usage[i]);
  299.  
  300. End;
  301. (*------------------------------------------------------------------------*)
  302.  
  303.  
  304. (*------------------------------------------------------------------------*)
  305. (*                      MAIN PROGRAM                                      *)
  306. (*------------------------------------------------------------------------*)
  307. Var thekey : char;
  308.  
  309. BEGIN
  310.      Fin:=False;
  311.      Frozen:=False;
  312.      dist2screen:=5;
  313.      InitVid;
  314.      DispDoc;
  315.      InitFace;
  316.      xi:=3;
  317.      yi:=4;
  318.      zi:=5;
  319.      Repeat
  320.            If KeyPressed then
  321.               Begin
  322.                    thekey:=ReadKey;
  323.                    case thekey of
  324.                         '6' : if NOT( Frozen) then yi:=yi + 1;
  325.                         '4' : if NOT( Frozen) AND (yi > 0) then
  326.                                  yi:=yi - 1;
  327.  
  328.                         '8' : if NOT( Frozen) then xi:=xi + 1;
  329.                         '2' : if NOT( Frozen) AND (xi > 0) then
  330.                                  xi:=xi - 1;
  331.  
  332.                         '9' : if NOT( Frozen) then zi:=zi + 1;
  333.                         '1' : if NOT( Frozen) AND (zi > 0) then
  334.                                  zi:=zi - 1;
  335.  
  336.                         '+' : if NOT( Frozen) AND (dist2screen > 0) then
  337.                                  dist2screen:=dist2screen - 1;
  338.  
  339.                         '-' : if NOT( Frozen) AND (dist2screen < 40) then
  340.                                  dist2screen:=dist2screen + 1;
  341.                         'F',
  342.                         'f' : Begin
  343.                                    If NOT( Frozen) then
  344.                                       Begin
  345.                                            oldxi:=xi;
  346.                                            oldyi:=yi;
  347.                                            oldzi:=zi;
  348.                                            xi:=0;
  349.                                            yi:=0;
  350.                                            zi:=0;
  351.                                            Frozen:=true;
  352.                                       End
  353.                                    Else
  354.                                       Begin
  355.                                            xi:=oldxi;
  356.                                            yi:=oldyi;
  357.                                            zi:=oldzi;
  358.                                            Frozen:=false;
  359.                                       End;
  360.                               End;
  361.  
  362.                         #27 : Fin:=true
  363.                    end
  364.               End;
  365.            angle_x:=(angle_x + xi) mod 360;
  366.            angle_y:=(angle_y + yi) mod 360;
  367.            angle_z:=(angle_z + zi) mod 360;
  368.            delay( 15*3);
  369.            Rotate( angle_x, angle_y, angle_z, dist2screen);
  370.      Until Fin;
  371.      RestoreCrtMode
  372. END.
  373.